{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(101, 101)"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = np.genfromtxt('example.dat', delimiter = ',')\n",
    "data.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-1.146, -1.292,  0.849,  0.36 ,  0.261,  2.512,  2.319,  0.608,\n",
       "        0.343, -0.289,  0.704,  1.185, -1.443, -0.73 , -0.06 , -0.504,\n",
       "       -0.315,  0.946, -0.325, -0.092,  0.844,  0.326,  0.577, -0.125,\n",
       "       -0.553, -1.371, -0.857,  0.058,  0.275, -0.093,  0.287, -1.299,\n",
       "        0.669,  0.022,  0.286, -0.287,  0.543,  0.673, -0.673,  1.199,\n",
       "        1.356,  1.534, -0.612,  1.917,  1.896,  1.28 ,  0.601, -0.378,\n",
       "        0.349,  2.17 , -1.52 , -0.751, -0.546, -0.463,  0.284,  0.025,\n",
       "       -2.311, -0.432,  0.876, -0.076,  0.667,  1.655, -0.719,  1.394,\n",
       "        0.54 ,  0.553,  1.003, -0.763, -0.262, -1.323, -0.153, -0.308,\n",
       "        0.377,  0.021,  1.059, -0.304,  1.762, -1.381,  0.966, -0.347,\n",
       "        0.927, -1.054, -0.502,  0.12 ,  0.97 ,  2.02 ,  0.01 ,  0.657,\n",
       "       -1.012,  0.933, -1.921,  0.162, -0.606,  1.57 , -1.402, -0.653,\n",
       "       -0.084,  0.781,  1.553, -1.421,  1.192])"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(70, 101) (70, 1) (31, 101) (31, 1)\n"
     ]
    }
   ],
   "source": [
    "# 选择特征与标签\n",
    "x = data[:,0:100] \n",
    "y = data[:,100].reshape(-1,1)\n",
    "# 加一列\n",
    "X = np.column_stack((np.ones((x.shape[0],1)),x))\n",
    "\n",
    "# 划分训练集与测试集\n",
    "X_train, y_train = X[:70], y[:70]\n",
    "X_test, y_test = X[70:], y[70:]\n",
    "print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义参数初始化函数\n",
    "def initialize(dims):\n",
    "    w = np.zeros((dims, 1))\n",
    "    b = 0\n",
    "    return w, b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义符号函数\n",
    "def sign(x):\n",
    "    if x > 0:\n",
    "        return 1\n",
    "    elif x < 0:\n",
    "        return -1\n",
    "    else:\n",
    "        return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0],\n",
       "       [0],\n",
       "       [0]])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 利用numpy对符号函数进行向量化\n",
    "vec_sign = np.vectorize(sign)\n",
    "vec_sign(np.zeros((3,1)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义lasso损失函数\n",
    "def l1_loss(X, y, w, b, alpha):\n",
    "    num_train = X.shape[0]\n",
    "    num_feature = X.shape[1]\n",
    "    y_hat = np.dot(X, w) + b\n",
    "    loss = np.sum((y_hat-y)**2)/num_train + np.sum(alpha*abs(w))\n",
    "    dw = np.dot(X.T, (y_hat-y)) /num_train + alpha * vec_sign(w)\n",
    "    db = np.sum((y_hat-y)) /num_train\n",
    "    return y_hat, loss, dw, db"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义训练过程\n",
    "def lasso_train(X, y, learning_rate=0.01, epochs=300):\n",
    "    loss_list = []\n",
    "    w, b = initialize(X.shape[1])\n",
    "    for i in range(1, epochs):\n",
    "        y_hat, loss, dw, db = l1_loss(X, y, w, b, 0.1)\n",
    "        w += -learning_rate * dw\n",
    "        b += -learning_rate * db\n",
    "        loss_list.append(loss)\n",
    "        \n",
    "        if i % 300 == 0:\n",
    "            print('epoch %d loss %f' % (i, loss))\n",
    "        params = {\n",
    "            'w': w,\n",
    "            'b': b\n",
    "        }\n",
    "        grads = {\n",
    "            'dw': dw,\n",
    "            'db': db\n",
    "        }\n",
    "    return loss, loss_list, params, grads"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 300 loss 1.673867\n",
      "epoch 600 loss 1.555281\n",
      "epoch 900 loss 1.524316\n",
      "epoch 1200 loss 1.511976\n",
      "epoch 1500 loss 1.509368\n",
      "epoch 1800 loss 1.508463\n",
      "epoch 2100 loss 1.508338\n",
      "epoch 2400 loss 1.508864\n",
      "epoch 2700 loss 1.509530\n"
     ]
    }
   ],
   "source": [
    "# 执行训练示例\n",
    "loss, loss_list, params, grads = lasso_train(X_train, y_train, 0.01, 3000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'b': -0.24041528707142965, 'w': array([[-0.   ],\n",
       "        [-0.   ],\n",
       "        [ 0.594],\n",
       "        [ 0.634],\n",
       "        [ 0.001],\n",
       "        [ 0.999],\n",
       "        [-0.   ],\n",
       "        [ 0.821],\n",
       "        [-0.238],\n",
       "        [ 0.001],\n",
       "        [ 0.   ],\n",
       "        [ 0.792],\n",
       "        [ 0.   ],\n",
       "        [ 0.738],\n",
       "        [-0.   ],\n",
       "        [-0.129],\n",
       "        [ 0.   ],\n",
       "        [ 0.784],\n",
       "        [-0.001],\n",
       "        [ 0.82 ],\n",
       "        [ 0.001],\n",
       "        [ 0.001],\n",
       "        [ 0.   ],\n",
       "        [ 0.561],\n",
       "        [ 0.   ],\n",
       "        [-0.001],\n",
       "        [-0.   ],\n",
       "        [-0.001],\n",
       "        [ 0.   ],\n",
       "        [ 0.488],\n",
       "        [-0.   ],\n",
       "        [-0.   ],\n",
       "        [-0.   ],\n",
       "        [ 0.001],\n",
       "        [-0.001],\n",
       "        [-0.001],\n",
       "        [ 0.   ],\n",
       "        [-0.   ],\n",
       "        [ 0.001],\n",
       "        [-0.001],\n",
       "        [-0.001],\n",
       "        [-0.   ],\n",
       "        [ 0.001],\n",
       "        [-0.001],\n",
       "        [-0.006],\n",
       "        [ 0.002],\n",
       "        [ 0.001],\n",
       "        [-0.001],\n",
       "        [-0.   ],\n",
       "        [ 0.028],\n",
       "        [-0.001],\n",
       "        [ 0.   ],\n",
       "        [ 0.001],\n",
       "        [-0.   ],\n",
       "        [ 0.001],\n",
       "        [-0.065],\n",
       "        [ 0.251],\n",
       "        [-0.   ],\n",
       "        [-0.044],\n",
       "        [-0.   ],\n",
       "        [ 0.106],\n",
       "        [ 0.03 ],\n",
       "        [ 0.001],\n",
       "        [ 0.   ],\n",
       "        [-0.   ],\n",
       "        [-0.001],\n",
       "        [ 0.   ],\n",
       "        [ 0.   ],\n",
       "        [-0.001],\n",
       "        [ 0.132],\n",
       "        [ 0.239],\n",
       "        [-0.001],\n",
       "        [ 0.   ],\n",
       "        [ 0.169],\n",
       "        [ 0.001],\n",
       "        [ 0.013],\n",
       "        [ 0.001],\n",
       "        [-0.   ],\n",
       "        [ 0.002],\n",
       "        [ 0.001],\n",
       "        [-0.   ],\n",
       "        [ 0.202],\n",
       "        [-0.001],\n",
       "        [ 0.   ],\n",
       "        [-0.001],\n",
       "        [-0.042],\n",
       "        [-0.106],\n",
       "        [-0.   ],\n",
       "        [ 0.025],\n",
       "        [-0.111],\n",
       "        [ 0.   ],\n",
       "        [-0.001],\n",
       "        [ 0.134],\n",
       "        [ 0.001],\n",
       "        [ 0.   ],\n",
       "        [-0.055],\n",
       "        [-0.   ],\n",
       "        [ 0.095],\n",
       "        [ 0.   ],\n",
       "        [-0.178],\n",
       "        [ 0.067]])}"
      ]
     },
     "execution_count": 100,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 获取训练参数\n",
    "params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.469],\n",
       "       [-2.869],\n",
       "       [ 0.446],\n",
       "       [-0.552],\n",
       "       [-3.158]])"
      ]
     },
     "execution_count": 101,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 定义预测函数\n",
    "def predict(X, params):\n",
    "    w = params['w']\n",
    "    b = params['b']\n",
    "    \n",
    "    y_pred = np.dot(X, w) + b\n",
    "    return y_pred\n",
    "\n",
    "y_pred = predict(X_test, params)\n",
    "y_pred[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.247],\n",
       "       [-4.257],\n",
       "       [ 2.386],\n",
       "       [-1.878],\n",
       "       [-3.414]])"
      ]
     },
     "execution_count": 95,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_test[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.5704547131357188"
      ]
     },
     "execution_count": 102,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import r2_score\n",
    "r2_score(y_pred, y_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 简单绘图\n",
    "import matplotlib.pyplot as plt\n",
    "f = X_test.dot(params['w']) + params['b']\n",
    "\n",
    "plt.scatter(range(X_test.shape[0]), y_test)\n",
    "plt.plot(f, color = 'darkorange')\n",
    "plt.xlabel('X')\n",
    "plt.ylabel('y')\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 训练过程中的损失下降\n",
    "plt.plot(loss_list, color = 'blue')\n",
    "plt.xlabel('epochs')\n",
    "plt.ylabel('loss')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sklearn Lasso intercept : [-0.238]\n",
      "\n",
      "sklearn Lasso coefficients :\n",
      " [ 0.    -0.     0.598  0.642  0.     1.007 -0.     0.818 -0.228  0.\n",
      "  0.     0.794  0.     0.741 -0.    -0.125 -0.     0.794  0.     0.819\n",
      "  0.     0.    -0.     0.567 -0.    -0.    -0.    -0.    -0.     0.495\n",
      "  0.     0.     0.     0.    -0.    -0.    -0.    -0.    -0.    -0.\n",
      "  0.    -0.     0.    -0.    -0.008  0.     0.    -0.    -0.     0.02\n",
      "  0.    -0.     0.    -0.     0.    -0.068  0.246  0.    -0.042 -0.\n",
      "  0.105  0.032  0.     0.     0.    -0.    -0.     0.    -0.     0.125\n",
      "  0.234 -0.     0.     0.169  0.     0.016  0.    -0.     0.     0.\n",
      " -0.     0.201 -0.    -0.     0.    -0.041 -0.107 -0.     0.024 -0.108\n",
      " -0.    -0.     0.123  0.     0.    -0.059 -0.     0.094 -0.    -0.178\n",
      "  0.066]\n",
      "\n",
      "sklearn Lasso number of iterations : 24\n"
     ]
    }
   ],
   "source": [
    "# 导入线性模型模块\n",
    "from sklearn import linear_model\n",
    "# 创建lasso模型实例\n",
    "sk_lasso = linear_model.Lasso(alpha=0.1)\n",
    "# 对训练集进行拟合\n",
    "sk_lasso.fit(X_train, y_train)\n",
    "# 打印模型相关系数\n",
    "print(\"sklearn Lasso intercept :\", sk_lasso.intercept_)\n",
    "print(\"\\nsklearn Lasso coefficients :\\n\", sk_lasso.coef_)\n",
    "print(\"\\nsklearn Lasso number of iterations :\", sk_lasso.n_iter_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
